#pragma once

#include <cmath>
#include <vector>
#include "Math.h"

struct Point 
{
	Point()
	{
		this->x = .0f; 
		this->y = .0f;
	}
	Point(float x,float y)
	{
		this->x = x; 
		this->y = y;
	}
	Point operator+(const Point& other) const
	{
		Point result = other;
		result.x += x;
		result.y += y;
		return result;
	}
	Point operator-(const Point& other) const
	{
		Point result = other;
		result.x -= x;
		result.y -= y;
		return result;
	}
	bool operator>(const Point& other) const
	{
		return this->x>other.x || this->y>other.y;
	}
	bool operator==(const Point& other) const 
	{
		return Math::Equal(x,other.x ) && Math::Equal(y,other.y );
	}
	float x;
	float y;
};

struct Line
{
	Line()
	{
	}
	Line(Point begin,Point end)
	{
		this->begin = begin;
		this->end = end;
	}

	Point begin;
	Point end;
};

struct Size
{
	Size()
	{
		this->cx = .0f; 
		this->cy = .0f;
	}
	Size(float cx,float cy)
	{
		this->cx = cx; 
		this->cy = cy;
	}
	Size(const Point& leftTop,const Point& rightBotton)
	{
		this->cx = (float)fabs(rightBotton.x-leftTop.x);
		this->cy = (float)fabs(rightBotton.y-leftTop.y);
	}
	bool operator>(const Size& other) const
	{
		return this->cx>other.cx || this->cy>other.cy;
	}
	bool operator==(const Size& other) const 
	{
		return Math::Equal(cx,other.cx ) && Math::Equal(cy,other.cy );
	}
	float cx;
	float cy;
};

struct Rect
{
public:
	Rect(){left = top = right = bottom = .0f;}
	Rect(real left,real top,real right,real bottom)
	{
		this->left = left;
		this->top = top;
		this->right = right;
		this->bottom = bottom;
	}
	Rect(const Point& leftTop,const Size& size)
	{
		this->left = leftTop.x;
		this->top = leftTop.y;
		this->right = leftTop.x+size.cx;
		this->bottom = leftTop.y+size.cy;
	}

	Rect(const Point& leftTop,const Point& rightBotton)
	{
		Point first = leftTop>rightBotton ? rightBotton : leftTop;//normalize first
		Point second = leftTop>rightBotton ? leftTop : rightBotton ;//normalize first
		this->left = first.x;
		this->top = first.y;
		this->right = second.x;
		this->bottom = second.y;
	}

	Rect& operator+=(const Size& size)
	{
		this->left -= size.cx;
		this->top -= size.cy;
		this->right += size.cx;
		this->bottom += size.cy;
		return *this;
	}

	Rect& operator-=(const Size& size)
	{
		this->left += size.cx;
		this->top += size.cy;
		this->right -= size.cx;
		this->bottom -= size.cy;
		return *this;
	}

	bool operator==(const Rect& other) const 
	{
		return Math::Equal(left,other.left) 
			&&   Math::Equal(top,other.top)
			&&   Math::Equal(right,other.right) 
			&&   Math::Equal(bottom,other.bottom);
	}
	Rect& Inflect(const Rect& other)
	{
		if (this==&other)
			return *this;

		this->left -= other.left;
		this->top -= other.top;
		this->right += other.right;
		this->bottom += other.bottom;
		return *this;
	}

	Rect& Deflect(const Rect& other)
	{
		if (this==&other)
			return *this;

		this->left += other.left;
		this->top += other.top;
		this->right -= other.right;
		this->bottom -= other.bottom;
		return *this;
	}

	Rect& Union(const Rect& other)
	{
		if (this==&other)
			return *this;

		//left,top less
		if (Math::Greater(this->left,other.left))
			this->left = other.left;
		if (Math::Greater(this->top,other.top))
			this->top = other.top;

		//right bottom,greater
		if (Math::Less(this->right,other.right))
			this->right = other.right;
		if (Math::Less(this->bottom,other.bottom))
			this->bottom = other.bottom;

		return *this;
	}

	bool operator>=(const Rect& other) const
	{
		return (left<=other.left && top<=other.top && right>=other.right && bottom>=other.bottom);
	}

	bool operator<=(const Rect& other) const
	{
		return (left>=other.left && top>=other.top && right<=other.right && bottom<=other.bottom);
	}

	bool operator>(const Rect& other) const
	{
		return !operator<=(other);
	}

	bool operator<(const Rect& other) const
	{
		return !operator>=(other);
	}

	float X() const {return left;}
	float Y() const {return top;}

	float Width() const {return right-left;}
	float Height() const {return bottom-top;}

	Size GetSize() const {return Size(Width(),Height());}

	Point LeftTop() const {return Point(left,top);}
	Point RightBottom() const {return Point(right,bottom);}
	Point RightTop() const {return Point(right,top);}
	Point LeftBottom() const {return Point(left,bottom);}

	float left;
	float top;
	float right;
	float bottom;
};

typedef std::vector<Point> Points;
typedef std::vector<Rect> Rects;